﻿using System;

namespace IupNET
{
    public class Tree:Control
    {

        public readonly TreeNode Root;
        private long unique_count = 0;

        public Tree()
            : base(Iupc.Tree())
        {
            Root=  new TreeNode(0,this);
        }

        internal IntPtr GetUniqueID()
        {
            unique_count++;
            return new IntPtr(unique_count);
        }

        public bool AddExpanded
        {
            get
            {
                return GetAttribute("ADDEXPANDED") == "YES";
            }
            set
            {
                SetAttribute("ADDEXPANDED", value ? "YES" : "NO");
            }
        }

        public bool AutoDragDrop
        {
            get
            {
                return GetAttribute("AUTODRAGDROP") == "YES";
            }
            set
            {
                SetAttribute("AUTODRAGDROP", value ? "YES" : "NO");
                
            }
        }

        public int Count
        {
            get
            {
                return Convert.StringToInt(GetAttribute("COUNT"));
            }
        }

        public bool CanFocus
        {
            get
            {
                return GetAttribute("CANFOCUS") == "YES";
            }
            set
            {
                SetAttribute("CANFOCUS", value ? "YES" : "NO");
            }
        }

        public bool DragDrop
        {
            get
            {
                return GetAttribute("DRAGDROP") == "YES";
            }
            set
            {
                SetAttribute("DRAGDROP", value ? "YES" : "NO");
            }
        }

        public bool HideButtons
        {
            get
            {
                return GetAttribute("HIDEBUTTONS") == "YES";
            }
            set
            {
                SetAttribute("HIDEBUTTONS", value ? "YES" : "NO");
            }
        }

        public bool HideLines
        {
            get
            {
                return GetAttribute("HIDELINES") == "YES";
            }
            set
            {
                SetAttribute("HIDELINES", value ? "YES" : "NO");
            }
        }

        public int Indentation
        {
            get
            {
                return Convert.StringToInt(GetAttribute("INDENTATION"));
            }
            set
            {
                SetAttribute("INDENTATION", value.ToString());
            }
        }

        public bool ShowDragDrop
        {
            get
            {
                return GetAttribute("SHOWDRAGDROP") == "YES";
            }
            set
            {
                SetAttribute("SHOWDRAGDROP", value ? "YES" : "NO");
            }
        }

        public int Spacing
        {
            get
            {
                return Convert.StringToInt(GetAttribute("SPACING"));
            }
            set
            {
                SetAttribute("SPACING", value.ToString());
            }
        }

        public TreeNode TopItem
        {
            set
            {
                SetAttribute("TOPITEM", value.Index.ToString());
            }
        }

        /// <summary>
        /// Deletes the focused node from the tree.
        /// </summary>
        public void Delete()
        {
            SetAttribute("DELNODE" , "SELECTED");
        }

        /// <summary>
        /// Deletes the childrens of the focused node in the tree.
        /// </summary>
        public void DeleteChildren()
        {
            SetAttribute("DELNODE", "CHILDREN");
        }

        public void DeleteSelected()
        {
            SetAttribute("DELNODE", "MARKED");
        }

        public void ExpandAll() {
        
            SetAttribute("EXPANDALL", "YES");
        }

        public void CollapseAll() {
            SetAttribute("EXPANDALL", "FALSE");
        }


        public TreeNode Selected
        {
            get
            {
                int index=Convert.StringToInt(Value);
                IntPtr userid=Iupc.TreeGetUserId(cobject, index);
                return new TreeNode(this, userid);
            }

            set
            {
                int id=Iupc.TreeGetId(cobject, value.UserID);
                Value = id.ToString();

            }
        }

        public Image ImageLeaf
        {
            set
            {
                string n = value.HandleName;
                SetAttribute("IMAGELEAF", n);
            }
        }


        public Image ImageBranchCollapsed
        {
            set
            {
                string n = value.HandleName;
                SetAttribute("IMAGEBRANCHCOLLAPSED", n);
            }
        }

        public Image ImageBranchExpanded
        {
            set
            {
                string n = value.HandleName;
                SetAttribute("IMAGEBRANCHEXPANDED", n);
            }
        }

        public bool MultiSelect
        {
            get
            {
                return GetAttribute("MARKMODE") == "MULTIPLE";
            }
            set
            {
                SetAttribute("MARKMODE", value ? "MULTIPLE" : "SINGLE");
            }
        }

        public void Mark(TreeNode first, TreeNode last)
        {
            int a = first.Index;
            int b = last.Index;
            SetAttribute("MARK",a.ToString()+","+b.ToString());
        }

        public TreeNode this[int i] {
            get
            {
                IntPtr p=Iupc.TreeGetUserId(cobject, i);
                if (p == IntPtr.Zero)
                    return null;
                return new TreeNode(this, p);
            }


        }

        public void MarkAll()
        {
            SetAttribute("MARK", "MARKALL");
        }

        public void UnmarkAll()
        {
            SetAttribute("MARK", "CLEARALL");
        }


        public bool ShowRename
        {
            get
            {
                return GetAttribute("SHOWRENAME") == "YES";
            }
            set
            {
                SetAttribute("SHOWRENAME", value ? "YES" : "NO");
            }
        }

        public int RenameCaret
        {
            get
            {
                return Convert.StringToInt(GetAttribute("RENAMECARET"));
            }
        }

        public string RenameSelection
        { //TODO: implement better handleing of this, and support ALL and NONE options to
            get
            {
                return GetAttribute("RENAMESELECTION");
            }
            set
            {
                SetAttribute("RENAMESELECTION", value);
            }
        }

        public EventCallback SelectionCB
        {
            get
            {
                return CBHandler.Fetch("SELECTION_CB");
            }
            set
            {
                CBHandler.Set("SELECTION_CB", value);
            }
        }

        public EventCallback MultiSelectionCB
        {
            get
            {
                return CBHandler.Fetch("MULTISELECTION_CB");
            }
            set
            {
                CBHandler.Set("MULTISELECTION_CB", value);
            }
        }

        public EventCallback BranchOpenCB
        {
            get
            {
                return CBHandler.Fetch("BRANCHOPEN_CB");
            }
            set
            {
                CBHandler.Set("BRANCHOPEN_CB", value);
            }
        }

        public EventCallback BranchCloseCB
        {
            get
            {
                return CBHandler.Fetch("BRANCHCLOSE_CB");
            }
            set
            {
                CBHandler.Set("BRANCHCLOSE_CB", value);
            }
        }

        public EventCallback ExecuteLeafCB
        {
            get
            {
                return CBHandler.Fetch("EXECUTELEAF_CB");
            }
            set
            {
                CBHandler.Set("EXECUTELEAF_CB", value);
            }
        }

        public TreeNode ConvertXYToNode(int x, int y)
        {
            int id=Iupc.ConvertXYToPos(cobject, x, y);
            if (id < 0)
                return null;
            return this[id];
        }

        /// <summary>
        /// Action generated when a node is to be renamed and ShowRename=false. It occurs only when the user clicks twice the node or press F2.
        /// 
        /// Value: index of node renamed
        /// Text: the new name of the node
        /// </summary>
        public EventCallback RenameNodeCB
        {
            get
            {
                return CBHandler.Fetch("RENAMENODE_CB");
            }
            set
            {
                CBHandler.Set("RENAMENODE_CB", value);
            }
        }

        /// <summary>
        /// Action generated when a node is to be renamed in place and ShowRename=true. It occurs only when the user clicks twice the node or press F2.
        /// 
        /// Value: Index of the node to rename
        /// </summary>
        public EventCallback ShowRenameCB
        {
            get
            {
                return CBHandler.Fetch("SHOWRENAME_CB");
            }
            set
            {
                CBHandler.Set("SHOWRENAME_CB", value);
            }
        }

        /// <summary>
        /// Action generated after a node was renamed in place. It occurs when the user press Enter after editing the name, or when the text box looses it focus.
        /// 
        /// Value: index of node renamed.
        /// Text: the current name of the node.
        /// </summary>
        public EventCallback RenameCB
        {
            get
            {
                return CBHandler.Fetch("RENAME_CB");
            }
            set
            {
                CBHandler.Set("RENAME_CB", value);
            }
        }


        public EventCallback DragDropCB
        {
            get
            {
                return CBHandler.Fetch("DRAGDROP_CB");
            }
            set
            {
                CBHandler.Set("DRAGDROP_CB", value);
            }
        }

        public EventCallback RightClickCB
        {
            get
            {
                return CBHandler.Fetch("RIGHTCLICK_CB");
            }
            set
            {
                CBHandler.Set("RIGHTCLICK_CB", value);
            }
        }

        public EventCallback ButtonCB
        {
            get
            {
                return CBHandler.Fetch("BUTTON_CB");
            }
            set
            {
                CBHandler.Set("BUTTON_CB", value);
            }
        }

        public EventCallback MotionCB
        {
            get
            {
                return CBHandler.Fetch("MOTION_CB");
            }
            set
            {
                CBHandler.Set("MOTION_CB", value);
            }
        }

        public EventCallback DropFilesCB
        {
            get
            {
                return CBHandler.Fetch("DROPFILES_CB");
            }
            set
            {
                CBHandler.Set("DROPFILES_CB", value);
            }
        }
        
    }

    public class TreeNode
    {

        Tree Owner;
        public IntPtr UserID;

        
        internal TreeNode(int id,Tree owner)
        {
            
          
            Owner = owner;
            UserID = Owner.GetUniqueID();
            Iupc.TreeSetUserId(Owner.cobject, id, UserID);
        }

        internal TreeNode(Tree owner, IntPtr userid)
        {

            
            Owner = owner;
            UserID = userid;
            
        }

        public override int GetHashCode()
        {
          return base.GetHashCode();
        }
        
      public override bool Equals(object obj)
        {
          return this == obj as TreeNode;
        }

        public int Index
        {
            get
            {
                return Iupc.TreeGetId(Owner.cobject, UserID);
            }
        }

       

        /// <summary>
        /// Adds a leaf as a child to this node. If this node is a leaf, the new node is added as a brother _after_ this node.
        /// </summary>
        
        public TreeNode AddLeaf(string text)
        {
            int newid = Index + ChildCount;

            Owner.SetAttribute("ADDLEAF" + newid.ToString(), text);

            return new TreeNode(newid+1, Owner);
        }

        /// <summary>
        /// Adds a branch as a child to this node. If this node is a leaf, the new node is added as a brother _after_ this node.
        /// </summary>
        public TreeNode AddBranch(string text)
        {
            int newid = Index + ChildCount;

            Owner.SetAttribute("ADDBRANCH" + newid.ToString(), text);

            return new TreeNode(newid + 1, Owner);
        }

        public void Delete()
        {
            Owner.SetAttribute("DELNODE" + Index.ToString(), "SELECTED");
        }

        public void DeleteChildren()
        {
            Owner.SetAttribute("DELNODE" + Index.ToString(), "CHILDREN");
        }


        private void AssignUserIDSRecursivly(ref int id)
        {
            //used to assign new user id:s to nodes from copy etc.
            if (Iupc.TreeGetUserId(Owner.cobject, id) == IntPtr.Zero)
                Iupc.TreeSetUserId(Owner.cobject, id, Owner.GetUniqueID());

            int n = Convert.StringToInt(Owner.GetAttribute("CHILDCOUNT" + id.ToString()));
            id++;

            for (int l = 0; l < n; l++)
            {
                AssignUserIDSRecursivly(ref id);
            }
        }

        public TreeNode Copy(TreeNode target)
        {
            int newid = target.Index+1;
            Owner.SetAttribute("COPYNODE" + Index.ToString(), target.Index.ToString());
            AssignUserIDSRecursivly(ref newid);

            return new TreeNode(newid, Owner);
        }

        public TreeNode Move(TreeNode target)
        {
            int newid = target.Index + 1;
            Owner.SetAttribute("MOVENODE" + Index.ToString(), target.Index.ToString());
            AssignUserIDSRecursivly(ref newid);

            return new TreeNode(newid, Owner);
        }

        /// <summary>
        /// Inserts a leaf at the position of this node.
        /// </summary>
        public TreeNode InsertLeaf(string text)
        {
            int newid = Index-1;
            if (Iupc.GetAttribute(Owner.cobject,"KIND"+newid.ToString())=="LEAF")
                Owner.SetAttribute("INSERTLEAF" + newid.ToString(), text);
            else
                Owner.SetAttribute("ADDLEAF" + newid.ToString(), text);

            return new TreeNode(newid+1, Owner);
        }


        /// <summary>
        /// Inserts a branch at the position of this node.
        /// </summary>
        public TreeNode InsertBranch(string text)
        {
            int newid = Index - 1;
            if (Iupc.GetAttribute(Owner.cobject, "KIND" + newid.ToString()) == "LEAF")
                Owner.SetAttribute("INSERTBRANCH" + newid.ToString(), text);
            else
                Owner.SetAttribute("ADDBRANCH" + newid.ToString(), text);

            return new TreeNode(newid + 1, Owner);
        }


        public int ChildCount
        {
            get
            {
                return Convert.StringToInt(Owner.GetAttribute("CHILDCOUNT" + Index.ToString()));
            }
        }

        public Color Color
        {

            get
            {
                return Convert.StringToColor(Owner.GetAttribute("COLOR" + Index.ToString()));
            }
            set
            {
                Owner.SetAttribute("COLOR" + Index.ToString(), Convert.ColorToString(value));
            }
        }

        public int Depth
        {
            get
            {
                return Convert.StringToInt(Owner.GetAttribute("DEPTH" + Index.ToString()));
            }
        }

        

        public bool Leaf
        {
            get
            {
                return Owner.GetAttribute("KIND" + Index.ToString()) == "LEAF";
            }
        }

        public TreeNode Parent
        {
            get
            {
                int parentid = Convert.StringToInt(Owner.GetAttribute("PARENT" + Index.ToString()));
                TreeNode n = new TreeNode(Owner,Iupc.TreeGetUserId(Owner.cobject, parentid));
                return n;
            }
        }

        public bool Expanded
        {
            get
            {
                return Owner.GetAttribute("STATE"+Index.ToString()) == "EXPANDED";
            }
            set
            {
                Owner.SetAttribute("STATE"+Index.ToString(), value ? "EXPANDED" : "COLLAPSED");
            }
        }

        public string Title
        {
            get
            {
                return Owner.GetAttribute("TITLE" + Index.ToString());
            }
            set
            {
                Owner.SetAttribute("TITLE" + Index.ToString(), value);
            }
        }

        public string TitleFont
        {
            get
            {
                return Owner.GetAttribute("TITLEFONT" + Index.ToString());
            }
            set
            {
                Owner.SetAttribute("TITLEFONT" + Index.ToString(), value);
            }
        }

        public static bool operator ==(TreeNode a, TreeNode b)
        {
            if ((object)a==null)
                return (object)b == null;
            if ((object)b == null)
                return false;
            return a.UserID== b.UserID;
        }

        public static bool operator !=(TreeNode a, TreeNode b)
        {
            return !(a == b);
        }

        //TODO: userdata hack

        public Image Image
        {
            set
            {
                string n = value.HandleName;
                Owner.SetAttribute("IMAGE"+Index.ToString(), n);
            }
        }

        public Image ImageExpanded
        {
            set
            {
                string n = value.HandleName;
                Owner.SetAttribute("IMAGEEXPANDED" + Index.ToString(), n);
            }
        }

        public bool Marked
        {
            get
            {
                return Owner.GetAttribute("MARKED"+Index.ToString()) == "YES";
            }
            set
            {
                Owner.SetAttribute("MARKED"+Index.ToString(), value ? "YES" : "NO");
            }
        }


        public void Rename()
        {
            Owner.SetAttribute("RENAME", "");
        }


        


    }
}
